package ar.edu.caece.compiler.grammar.factories;

import ar.edu.caece.compiler.grammar.AbstractTokenVisitorFactory;
import ar.edu.caece.compiler.grammar.Recognizer;
import ar.edu.caece.compiler.grammar.TokenRecognizer;
import ar.edu.caece.compiler.grammar.TokenVisitor;
import ar.edu.caece.compiler.grammar.attributes.Attribute;
import ar.edu.caece.compiler.grammar.attributes.BooleanAttribute;
import ar.edu.caece.compiler.grammar.attributes.tree.NodeFuncProc;
import ar.edu.caece.compiler.grammar.attributes.tree.NodeListaBloques;
import ar.edu.caece.compiler.grammar.nonterminals.BLOQUE;
import ar.edu.caece.compiler.grammar.nonterminals.LISTABLOQUES;
import ar.edu.caece.compiler.grammar.nonterminals.LISTABLOQUES1;

public class LISTABLOQUES1Factory extends AbstractTokenVisitorFactory {

	private static LISTABLOQUES1Factory INSTANCE;
	
	public static LISTABLOQUES1Factory getInstance() throws Exception {
		if(INSTANCE==null) INSTANCE = new LISTABLOQUES1Factory();
		return INSTANCE;
	}
	
	private BLOQUEFactory bloqueFactory;
	private LISTABLOQUESFactory listabloquesFactory;
	private TokenVisitor parseBLOQUE;
	private TokenVisitor parseLISTABLOQUES;
	
	private Initializer initializer = new Initializer() {
		
		@Override
		public void init() throws Exception {
			initializer = NoOperationInitializer.getInstance();
			bloqueFactory = BLOQUEFactory.getInstance();
			listabloquesFactory = LISTABLOQUESFactory.getInstance();
			parseLISTABLOQUES = listabloquesFactory.makeVisitor();
			parseBLOQUE = bloqueFactory.makeVisitor();
		}
	};
	
	private LISTABLOQUES1Factory() throws Exception {

	}
	
	@Override
	public TokenVisitor makeChainedVisitor(
			final TokenVisitor siguiente) throws Exception {
		initializer.init();

		return new TokenVisitor() {

			@Override
			public Recognizer defaultCase(TokenRecognizer llamador)
					throws Exception {
				TokenVisitor parseBLOQUE2 = bloqueFactory.makeChainedVisitor(siguiente);
				parseBLOQUE2.addInheretedAttribute(Attribute.TABLA_SIMBOLOS_HEREDADA,getAttribute(Attribute.TABLA_SIMBOLOS_HEREDADA));
				parseBLOQUE2.addInheretedAttribute(Attribute.ARBOL_HEREDADO, getAttribute(Attribute.ARBOL_HEREDADO));
				Recognizer result = llamador.execute(parseBLOQUE2);
				if(result instanceof BLOQUE) {
					
					
					BLOQUE bloque = (BLOQUE) result;
					parseLISTABLOQUES.addInheretedAttribute(Attribute.TABLA_SIMBOLOS_HEREDADA,bloque.getAttribute(Attribute.TABLA_SIMBOLOS_SINTETIZADA));

					parseLISTABLOQUES.addInheretedAttribute("ultimo",bloque.getAttribute("ultimo"));
					
					if(!((BooleanAttribute) bloque.getAttribute("ultimo")).getValue()) {
						NodeFuncProc bloqueProcFunc = (NodeFuncProc) bloque.getAttribute(Attribute.ARBOL_SINTETIZADO);
						NodeListaBloques listaBloques = (NodeListaBloques) getAttribute(Attribute.ARBOL_HEREDADO);
						
						listaBloques.addBloque(bloqueProcFunc);
						parseLISTABLOQUES.addInheretedAttribute(Attribute.ARBOL_HEREDADO, listaBloques);

					} else {
						
						NodeFuncProc principal = (NodeFuncProc) bloque.getAttribute(Attribute.ARBOL_SINTETIZADO);
						NodeListaBloques listaBloques = (NodeListaBloques) getAttribute(Attribute.ARBOL_HEREDADO);
						
						listaBloques.setPrincipal(principal);
						parseLISTABLOQUES.addInheretedAttribute(Attribute.ARBOL_HEREDADO, listaBloques);
					}
					
					LISTABLOQUES listabloques = (LISTABLOQUES) nextToken().execute(parseLISTABLOQUES);
					LISTABLOQUES1 listabloques1 = new LISTABLOQUES1 (bloque, listabloques);
					
					listabloques1.addAttribute(Attribute.TABLA_SIMBOLOS_SINTETIZADA,listabloques.getAttribute(Attribute.TABLA_SIMBOLOS_SINTETIZADA));
					listabloques1.addAttribute("ultimo", bloque.getAttribute("ultimo"));
					listabloques1.addAttribute(Attribute.ARBOL_SINTETIZADO, listabloques.getAttribute(Attribute.ARBOL_SINTETIZADO));
					return listabloques1;			
					} 
				else {
					return result;
				}
			}
			
		};
	
	}
	@Override
	public TokenVisitor makeVisitor() throws Exception {
		initializer.init();

		return new TokenVisitor() {

			@Override
			public Recognizer defaultCase(TokenRecognizer llamador) throws Exception {
				parseBLOQUE.addInheretedAttribute(Attribute.TABLA_SIMBOLOS_HEREDADA,getAttribute(Attribute.TABLA_SIMBOLOS_HEREDADA));
				parseBLOQUE.addInheretedAttribute(Attribute.ARBOL_HEREDADO, getAttribute(Attribute.ARBOL_HEREDADO));
				
				BLOQUE bloque = (BLOQUE) llamador.execute(parseBLOQUE);
				parseLISTABLOQUES.addInheretedAttribute(Attribute.TABLA_SIMBOLOS_HEREDADA,bloque.getAttribute(Attribute.TABLA_SIMBOLOS_SINTETIZADA));

				parseLISTABLOQUES.addInheretedAttribute("ultimo",bloque.getAttribute("ultimo"));
				
				if(!((BooleanAttribute) bloque.getAttribute("ultimo")).getValue()) {
					NodeFuncProc bloqueProcFunc = (NodeFuncProc) bloque.getAttribute(Attribute.ARBOL_SINTETIZADO);
					NodeListaBloques listaBloques = (NodeListaBloques) getAttribute(Attribute.ARBOL_HEREDADO);
					
					listaBloques.addBloque(bloqueProcFunc);
					parseLISTABLOQUES.addInheretedAttribute(Attribute.ARBOL_HEREDADO, listaBloques);

				} else {
					
					NodeFuncProc principal = (NodeFuncProc) bloque.getAttribute(Attribute.ARBOL_SINTETIZADO);
					NodeListaBloques listaBloques = (NodeListaBloques) getAttribute(Attribute.ARBOL_HEREDADO);
					
					listaBloques.setPrincipal(principal);
					parseLISTABLOQUES.addInheretedAttribute(Attribute.ARBOL_HEREDADO, listaBloques);
				}
				
				LISTABLOQUES listabloques = (LISTABLOQUES) nextToken().execute(parseLISTABLOQUES);
				LISTABLOQUES1 listabloques1 = new LISTABLOQUES1 (bloque, listabloques);
				
				listabloques1.addAttribute(Attribute.TABLA_SIMBOLOS_SINTETIZADA,listabloques.getAttribute(Attribute.TABLA_SIMBOLOS_SINTETIZADA));
				listabloques1.addAttribute("ultimo", bloque.getAttribute("ultimo"));
				listabloques1.addAttribute(Attribute.ARBOL_SINTETIZADO, listabloques.getAttribute(Attribute.ARBOL_SINTETIZADO));
				return listabloques1;
			}
		};
	}
	
	
}
